package com.newtouch.cq.security.token;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.newtouch.cq.lang.cache.CacheAble;
import com.newtouch.cq.lang.config.TokenCacheProperties;
import com.newtouch.cq.lang.em.BaseExceptionEnum;
import com.newtouch.cq.lang.exception.MccBizException;
import com.newtouch.cq.lang.user.BaseUserDetails;
import com.newtouch.cq.lang.util.LogUtil;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.LinkedList;

/**
 * token缓存工具类
 *
 * @author alex
 * @Date: 2021/1/23
 */
@Component
public class TokenCache<T extends BaseUserDetails & UserDetails> {

    private static Log log = LogFactory.get(TokenCache.class);

    @Resource
    private CacheAble cacheAble;

    /**
     * 通过tokenKey获取登陆者信息
     *
     * @param userKey
     * @param tokenKey
     * @return
     */
    public  T loadByTokenOrThrow(String userKey, String tokenKey) {
        T user = null;
        if (cacheAble.hasKey(userKey)) {
            LogUtil.error(log, BaseExceptionEnum.ACCREDIT_INVALID_OVERDUE);
            throw new MccBizException(BaseExceptionEnum.ACCREDIT_INVALID_OVERDUE);
        }
        LinkedList<String> userTokens = (LinkedList<String>) cacheAble.get(userKey);
        if(CollUtil.isEmpty(userTokens)) {
            LogUtil.error(log,BaseExceptionEnum.ACCREDIT_INVALID_OVERDUE);
            throw new MccBizException(BaseExceptionEnum.ACCREDIT_INVALID_OVERDUE);
        }
        if(!CollUtil.contains(userTokens,userKey)) {
            LogUtil.error(log,BaseExceptionEnum.ACCREDIT_INVALID_OVERDUE);
            throw new MccBizException(BaseExceptionEnum.ACCREDIT_INVALID_OVERDUE);
        }
        if(TokenCacheProperties.renewal) {
            cacheAble.get(userKey, TokenCacheProperties.timeOut+ TokenCacheProperties.timeOutDelay);
            user =  (T)cacheAble.get(tokenKey, TokenCacheProperties.timeOut+ TokenCacheProperties.timeOutDelay);
        } else {
            user = (T)cacheAble.get(tokenKey);
        }

        if(ObjectUtil.isNull(user)) {
            LogUtil.error(log,BaseExceptionEnum.ACCREDIT_INVALID_OVERDUE);
            throw new MccBizException(BaseExceptionEnum.ACCREDIT_INVALID_OVERDUE);
        }
        return user;
    }

    /**
     * 通过tokenKey获取登陆者信息
     *
     * @param userKey
     * @param tokenKey
     * @return
     */
    public T loadByToken(String userKey, String tokenKey) {
        if (!cacheAble.hasKey(userKey)) {
            return null;
        }
        LinkedList<String> userTokens = (LinkedList<String>) cacheAble.get(userKey);
        if(CollUtil.isEmpty(userTokens)) {
            return null;
        }
        if(!CollUtil.contains(userTokens,tokenKey)) {
            return null;
        }
        if(TokenCacheProperties.renewal) {
            cacheAble.get(userKey, TokenCacheProperties.timeOut+ TokenCacheProperties.timeOutDelay);
            return (T)cacheAble.get(tokenKey, TokenCacheProperties.timeOut+ TokenCacheProperties.timeOutDelay);
        }
        return (T)cacheAble.get(tokenKey);
    }


    /**
     * 缓存token
     *
     * @param userKey
     * @param tokenKey

     */
    public void saveToken(String userKey, String tokenKey, Object obj) {
        T userDetails = (T) obj;
        //设置过期时间
        userDetails.setTimeout(System.currentTimeMillis() +
                TokenCacheProperties.timeOut * DateUnit.SECOND.getMillis());

        //获取容器中的缓存服务
        LinkedList<String> userTokens = (LinkedList<String>) cacheAble.get(userKey);
        if (CollectionUtil.isEmpty(userTokens)) {
            userTokens = new LinkedList<>();
        }
        for (String userToken : userTokens) {
            if(!cacheAble.hasKey(userKey)) {
               CollUtil.removeAny(userTokens,userToken);
            }
        }
        if (TokenCacheProperties.maxOnlineCount > 0 && userTokens.size() >= TokenCacheProperties.maxOnlineCount) {
            cacheAble.delete(userTokens.getFirst());
            userTokens.removeFirst();
        }
        userTokens.add(tokenKey);
        cacheAble.put(userKey, userTokens, TokenCacheProperties.timeOut+ TokenCacheProperties.timeOutDelay);
        cacheAble.put(tokenKey, userDetails, TokenCacheProperties.timeOut+ TokenCacheProperties.timeOutDelay);
    }


    /**
     * 查询token是否存在
     * @param tokenKey
     * @return
     */
    public  boolean hasToken(String tokenKey) {
        //获取容器中的缓存服务
        return cacheAble.hasKey(tokenKey);
    }

    public  void delToken(String userKey, String tokenKey) {
        //获取容器中的缓存服务
        LinkedList<String> userTokens = (LinkedList<String>) cacheAble.get(userKey);
        CollUtil.removeAny(userTokens,tokenKey);
        cacheAble.put(userKey, userTokens, TokenCacheProperties.timeOut+ TokenCacheProperties.timeOutDelay);
        cacheAble.delete(tokenKey);
    }

}
